library(tidyverse)
There were 13 warnings (use warnings() to see them)
refrac <- read_tsv("/Users/jkim/Downloads/refract\ data\ -\ Sheet1 (3).tsv")
Rows: 147 Columns: 7── Column specification ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: "\t"
chr (4): Refract, Owner, Unit, Solution
dbl (3): Reading, Trial, Expected
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
refrac %>%
  ggplot(aes(x=Refract, y=Reading, color=Owner)) +
  geom_hline(aes(yintercept = Expected)) +
  geom_point() +
  facet_wrap(~Solution, scales="free_y")


refrac %>%
  ggplot(aes(x=Refract, y=Reading, color=Owner)) +
  geom_boxplot() +
  geom_hline(aes(yintercept = Expected)) +
  facet_wrap(~Solution, scales="free_y") +
  ggtitle("Comparison of refractometers")

  
refrac %>%
  ggplot() +
  geom_boxplot(aes(x=Refract, y=Reading, fill=Refract)) +
  geom_point(aes(x=Refract, y=Reading, color=Owner)) +
  geom_point(aes(x=Refract, y=Reading), pch=21, color="white") +
  geom_hline(aes(yintercept = Expected)) +
  facet_wrap(~Solution, scales="free_y") +
  ggtitle("Comparison of refractometers")

refrac %>%
  mutate(norm_reading = Reading / Expected) %>%
  ggplot(aes(x=Refract, y=norm_reading, color=Owner)) +
  geom_hline(yintercept = 1) +
  geom_point() +
  facet_wrap(~Solution, scales="free_y")


# normalize readings
refrac %>%
  filter(!is.na(Expected)) %>%
  mutate(norm_reading = Reading / Expected) %>%
  ggplot() +
  geom_boxplot(aes(x=Refract, y=norm_reading, color=Owner))


refrac %>%
  filter(!is.na(Expected)) %>%
  filter(Solution != "2% Folgers") %>%
  mutate(norm_reading = Reading / Expected) %>%
  ggplot() +
  geom_violin(aes(x=Refract, y=norm_reading, color=Owner))

Plot the error of each refractometer at different ratios

# Center and scale
refrac %>%
  group_by(Refract, Owner, Solution) %>%
  mutate(norm_reading = (Reading - mean(Reading))/mean(Reading) * 100) %>%
  ggplot() +
  geom_density(aes(norm_reading, fill = Refract), alpha=0.25) +
  ggtitle("Center and scaled readings by refractometer")+
  xlab("Percent error")


refrac %>%
  group_by(Refract, Owner, Solution) %>%
  mutate(norm_reading = (Reading - mean(Reading))/mean(Reading)) %>%
  ggplot(aes(x=Refract, y=norm_reading, color=Owner)) +
  geom_boxplot() +
  facet_wrap(~Solution) +
  ggtitle("Centered and scaled") +
  ylab("Centered and scaled")


refrac %>%
  filter(!Solution %in% c("Filter Brew", "2% Folgers")) %>%
  group_by(Refract, Owner, Solution) %>%
  mutate(norm_reading = (Reading - mean(Reading))/mean(Reading)) %>%
  ggplot(aes(x=Refract, y=norm_reading, color=Owner)) +
  geom_boxplot() +
  facet_wrap(~Solution) +
  ggtitle("Centered and scaled") +
  ylab("Centered and scaled")


# Known values only
refrac %>%
  filter(!is.na(Expected)) %>%
  group_by(Refract, Owner, Solution) %>%
  mutate(norm_reading = (Reading - Expected)/Expected * 100) %>%
  ggplot() +
  geom_density(aes(norm_reading, fill = Refract), alpha=0.25) +
  ggtitle("Error relative to expected value")+
  xlab("Percent error")


refrac %>%
  filter(!is.na(Expected)) %>%
  group_by(Refract, Owner, Solution) %>%
  mutate(norm_reading = (Reading - Expected)/Expected * 100) %>%
  ggplot(aes(x=Refract, y=norm_reading, color=Owner)) +
  geom_boxplot() +
  facet_wrap(~Solution) +
  ggtitle("Comparison of refractometers") +
  ylab("Percent error")


refrac %>%
  filter(!is.na(Expected)) %>%
  filter(Solution != "2% Folgers") %>%
  group_by(Refract, Owner, Solution) %>%
  mutate(norm_reading = (Reading - Expected)/Expected * 100) %>%
  ggplot(aes(x=Refract, y=norm_reading, color=Owner)) +
  geom_boxplot() +
  facet_wrap(~Solution) +
  ggtitle("Comparison of refractometers") +
  ylab("Percent error")


refrac %>%
  filter(!is.na(Expected)) %>%
  filter(Solution != "2% Folgers") %>%
  group_by(Refract, Owner, Solution) %>%
  mutate(norm_reading = (Reading - Expected)/Expected * 100) %>%
  ggplot() +
  geom_density(aes(norm_reading, fill = Refract), alpha=0.25) +
  ggtitle("No 2% Folgers")+
  xlab("Percent error")

# Let's see how the errors propogate to EY

ey_key <- tribble(
  ~Solution, ~ratio, ~type,
  "9.95% Folgers", 2, "9.95% Folgers",
  "9.95% Folgers 2", 2, "9.95% Folgers",
  "2% Folgers", 10, "2% Folgers"
  
)

refrac %>%
  filter(Solution %in% c("9.95% Folgers", "9.95% Folgers 2", "2% Folgers")) %>%
  left_join(ey_key, by="Solution") %>%
  mutate(predicted_ey = Reading * ratio) %>%
  mutate(expected_ey = Expected * ratio) %>%
  mutate(diff_from_expected = predicted_ey - expected_ey) %>%
  ggplot() +
  geom_density(aes(diff_from_expected, fill=Refract), alpha=0.25) +
  ggtitle("Error in Extraction Yield (%), Folgers Instant") +
  xlab("Observed EY - Expected EY")


refrac %>%
  filter(Solution %in% c("9.95% Folgers", "9.95% Folgers 2", "2% Folgers")) %>%
  left_join(ey_key, by="Solution") %>%
  mutate(predicted_ey = Reading * ratio) %>%
  mutate(expected_ey = Expected * ratio) %>%
  mutate(diff_from_expected = predicted_ey - expected_ey) %>%
  ggplot() +
  geom_point(aes(x=expected_ey, y=predicted_ey, color=Refract)) +
  ggtitle("Error in Extraction Yield(%), Folgers Instant")


ratio_expansion <- ey_key %>%
  expand(Solution, ratio=5:15) %>%
  left_join(select(ey_key, Solution, type))
Joining, by = "Solution"
refrac %>%
  filter(Solution %in% c("2% Folgers")) %>%
  left_join(ratio_expansion, by="Solution") %>%
  mutate(predicted_ey = Reading * ratio) %>%
  mutate(expected_ey = Expected * ratio) %>%
  mutate(diff_from_expected = predicted_ey - expected_ey) %>%
  group_by(expected_ey, Refract, ratio) %>%
  summarise(mean_obs = mean(predicted_ey),
            sd_high_obs = mean(predicted_ey) + sd(predicted_ey * 2),
            sd_low_obs = mean(predicted_ey) - sd(predicted_ey * 2)) %>%
  ungroup() %>%
  ggplot(aes(x=expected_ey, y=mean_obs, color=Refract)) +
  geom_line() +
  geom_ribbon(aes(ymin=sd_low_obs, ymax=sd_high_obs, fill=Refract), alpha=0.25, color=NA) +
  geom_abline() +
  ggtitle("Error in Extraction Yield(%), Folgers Instant 2% TD, 2 sd ribbon")
`summarise()` has grouped output by 'expected_ey', 'Refract'. You can override using the `.groups` argument.

refrac %>%
  filter(Solution %in% c("2% Folgers")) %>%
  left_join(ratio_expansion, by="Solution") %>%
  mutate(predicted_ey = Reading * ratio) %>%
  mutate(expected_ey = Expected * ratio) %>%
  mutate(diff_from_expected = predicted_ey - expected_ey) %>%
  group_by(Owner, expected_ey, Refract, ratio) %>%
  summarise(mean_obs = mean(predicted_ey),
            sd_high_obs = mean(predicted_ey) + sd(predicted_ey * 2),
            sd_low_obs = mean(predicted_ey) - sd(predicted_ey * 2)) %>%
  ungroup() %>%
  mutate(instrument = paste(Refract, Owner)) %>%
  ggplot(aes(x=expected_ey, y=mean_obs, color=instrument)) +
  geom_ribbon(aes(ymin=sd_low_obs, ymax=sd_high_obs, fill=instrument), alpha=0.25, color=NA) +
  geom_line() +
  geom_abline() +
  ggtitle("Error in Extraction Yield(%), Folgers Instant 2% TDS, 2 sd ribbon") +
  facet_wrap(~Refract, ncol=1)
`summarise()` has grouped output by 'Owner', 'expected_ey', 'Refract'. You can override using the `.groups` argument.

refrac %>%
  filter(Solution %in% c("2% Folgers")) %>%
  left_join(ratio_expansion, by="Solution") %>%
  mutate(predicted_ey = Reading * ratio) %>%
  mutate(expected_ey = Expected * ratio) %>%
  mutate(diff_from_expected = predicted_ey - expected_ey) %>%
  group_by(Owner, expected_ey, Refract, ratio) %>%
  summarise(med_obs = median(predicted_ey),
            high_obs = max(predicted_ey),
            low_obs = min(predicted_ey)) %>%
  ungroup() %>%
  mutate(instrument = paste(Refract, Owner)) %>%
  ggplot(aes(x=expected_ey, y=med_obs, color=instrument)) +
  geom_ribbon(aes(ymin=low_obs, ymax=high_obs, fill=instrument), alpha=0.25, color=NA) +
  geom_line() +
  geom_abline() +
  ggtitle("Error in Extraction Yield(%), Folgers Instant 2% TDS, min/max ribbon") +
  facet_wrap(~Refract)
`summarise()` has grouped output by 'Owner', 'expected_ey', 'Refract'. You can override using the `.groups` argument.

ratio_expansion <- ey_key %>%
  expand(Solution, ratio=(15:28)/10) %>%
  left_join(select(ey_key, Solution, type))
Joining, by = "Solution"
refrac %>%
  filter(Solution %in% c("9.95% Folgers", "9.95% Folgers 2")) %>%
    left_join(ratio_expansion, by="Solution") %>%
  mutate(predicted_ey = Reading * ratio) %>%
  mutate(expected_ey = Expected * ratio) %>%
  mutate(diff_from_expected = predicted_ey - expected_ey) %>%
  group_by(expected_ey, Refract, ratio) %>%
  summarise(mean_obs = mean(predicted_ey),
            sd_high_obs = mean(predicted_ey) + sd(predicted_ey) * 2,
            sd_low_obs = mean(predicted_ey) - sd(predicted_ey) * 2) %>%
  ungroup() %>%
  ggplot(aes(x=expected_ey, y=mean_obs, color=Refract)) +
  geom_line() +
  geom_abline() +
  geom_ribbon(aes(ymin=sd_low_obs, ymax=sd_high_obs, fill=Refract), alpha=0.25, color=NA) +
  ggtitle("Error in Extraction Yield(%), Folgers Instant 9.95% TDS, 2 sd ribbon")
`summarise()` has grouped output by 'expected_ey', 'Refract'. You can override using the `.groups` argument.

refrac %>%
  filter(Solution %in% c("9.95% Folgers", "9.95% Folgers 2")) %>%
    left_join(ratio_expansion, by="Solution") %>%
  mutate(predicted_ey = Reading * ratio) %>%
  mutate(expected_ey = Expected * ratio) %>%
  mutate(diff_from_expected = predicted_ey - expected_ey) %>%
  group_by(Owner, expected_ey, Refract, ratio) %>%
  summarise(mean_obs = mean(predicted_ey),
            sd_high_obs = mean(predicted_ey) + sd(predicted_ey) * 2,
            sd_low_obs = mean(predicted_ey) - sd(predicted_ey) * 2) %>%
    mutate(instrument = paste(Refract, Owner)) %>%
  ggplot(aes(x=expected_ey, y=mean_obs, color=instrument)) +
  geom_ribbon(aes(ymin=sd_low_obs, ymax=sd_high_obs, fill=instrument), alpha=0.25, color=NA) +
  geom_line() +
  geom_abline() +
  ggtitle("Error in Extraction Yield(%), Folgers Instant 9.95% TDS, 2 sd ribbon") +
  facet_wrap(~Refract, ncol=1)
`summarise()` has grouped output by 'Owner', 'expected_ey', 'Refract'. You can override using the `.groups` argument.

refrac %>%
  filter(Solution %in% c("9.95% Folgers", "9.95% Folgers 2")) %>%
  left_join(ratio_expansion, by="Solution") %>%
  mutate(predicted_ey = Reading * ratio) %>%
  mutate(expected_ey = Expected * ratio) %>%
  mutate(diff_from_expected = predicted_ey - expected_ey) %>%
  group_by(Owner, expected_ey, Refract, ratio) %>%
  summarise(med_obs = median(predicted_ey),
            high_obs = max(predicted_ey),
            low_obs = min(predicted_ey)) %>%
  ungroup() %>%
  mutate(instrument = paste(Refract, Owner)) %>%
  ggplot(aes(x=expected_ey, y=med_obs, color=instrument)) +
  geom_ribbon(aes(ymin=low_obs, ymax=high_obs, fill=instrument), alpha=0.25, color=NA) +
  geom_line() +
  geom_abline() +
  ggtitle("Error in Extraction Yield(%), Folgers Instant 9.95% TDS, min/max ribbon") +
  facet_wrap(~Refract, ncol=1)
`summarise()` has grouped output by 'Owner', 'expected_ey', 'Refract'. You can override using the `.groups` argument.

LS0tCnRpdGxlOiAiUmVmcmFjdG9tZXRlciIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQoKcmVmcmFjIDwtIHJlYWRfdHN2KCIvVXNlcnMvamtpbS9Eb3dubG9hZHMvcmVmcmFjdFwgZGF0YVwgLVwgU2hlZXQxICgzKS50c3YiKQpgYGAKCmBgYHtyfQpyZWZyYWMgJT4lCiAgZ2dwbG90KGFlcyh4PVJlZnJhY3QsIHk9UmVhZGluZywgY29sb3I9T3duZXIpKSArCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IEV4cGVjdGVkKSkgKwogIGdlb21fcG9pbnQoKSArCiAgZmFjZXRfd3JhcCh+U29sdXRpb24sIHNjYWxlcz0iZnJlZV95IikKCnJlZnJhYyAlPiUKICBnZ3Bsb3QoYWVzKHg9UmVmcmFjdCwgeT1SZWFkaW5nLCBjb2xvcj1Pd25lcikpICsKICBnZW9tX2JveHBsb3QoKSArCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IEV4cGVjdGVkKSkgKwogIGZhY2V0X3dyYXAoflNvbHV0aW9uLCBzY2FsZXM9ImZyZWVfeSIpICsKICBnZ3RpdGxlKCJDb21wYXJpc29uIG9mIHJlZnJhY3RvbWV0ZXJzIikKICAKcmVmcmFjICU+JQogIGdncGxvdCgpICsKICBnZW9tX2JveHBsb3QoYWVzKHg9UmVmcmFjdCwgeT1SZWFkaW5nLCBmaWxsPVJlZnJhY3QpKSArCiAgZ2VvbV9wb2ludChhZXMoeD1SZWZyYWN0LCB5PVJlYWRpbmcsIGNvbG9yPU93bmVyKSkgKwogIGdlb21fcG9pbnQoYWVzKHg9UmVmcmFjdCwgeT1SZWFkaW5nKSwgcGNoPTIxLCBjb2xvcj0id2hpdGUiKSArCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IEV4cGVjdGVkKSkgKwogIGZhY2V0X3dyYXAoflNvbHV0aW9uLCBzY2FsZXM9ImZyZWVfeSIpICsKICBnZ3RpdGxlKCJDb21wYXJpc29uIG9mIHJlZnJhY3RvbWV0ZXJzIikKYGBgCgpgYGB7cn0KcmVmcmFjICU+JQogIG11dGF0ZShub3JtX3JlYWRpbmcgPSBSZWFkaW5nIC8gRXhwZWN0ZWQpICU+JQogIGdncGxvdChhZXMoeD1SZWZyYWN0LCB5PW5vcm1fcmVhZGluZywgY29sb3I9T3duZXIpKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMSkgKwogIGdlb21fcG9pbnQoKSArCiAgZmFjZXRfd3JhcCh+U29sdXRpb24sIHNjYWxlcz0iZnJlZV95IikKCiMgbm9ybWFsaXplIHJlYWRpbmdzCnJlZnJhYyAlPiUKICBmaWx0ZXIoIWlzLm5hKEV4cGVjdGVkKSkgJT4lCiAgbXV0YXRlKG5vcm1fcmVhZGluZyA9IFJlYWRpbmcgLyBFeHBlY3RlZCkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYm94cGxvdChhZXMoeD1SZWZyYWN0LCB5PW5vcm1fcmVhZGluZywgY29sb3I9T3duZXIpKQoKcmVmcmFjICU+JQogIGZpbHRlcighaXMubmEoRXhwZWN0ZWQpKSAlPiUKICBmaWx0ZXIoU29sdXRpb24gIT0gIjIlIEZvbGdlcnMiKSAlPiUKICBtdXRhdGUobm9ybV9yZWFkaW5nID0gUmVhZGluZyAvIEV4cGVjdGVkKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV92aW9saW4oYWVzKHg9UmVmcmFjdCwgeT1ub3JtX3JlYWRpbmcsIGNvbG9yPU93bmVyKSkKYGBgCgoKClBsb3QgdGhlIGVycm9yIG9mIGVhY2ggcmVmcmFjdG9tZXRlciBhdCBkaWZmZXJlbnQgcmF0aW9zCmBgYHtyfQojIENlbnRlciBhbmQgc2NhbGUKcmVmcmFjICU+JQogIGdyb3VwX2J5KFJlZnJhY3QsIE93bmVyLCBTb2x1dGlvbikgJT4lCiAgbXV0YXRlKG5vcm1fcmVhZGluZyA9IChSZWFkaW5nIC0gbWVhbihSZWFkaW5nKSkvbWVhbihSZWFkaW5nKSAqIDEwMCkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fZGVuc2l0eShhZXMobm9ybV9yZWFkaW5nLCBmaWxsID0gUmVmcmFjdCksIGFscGhhPTAuMjUpICsKICBnZ3RpdGxlKCJDZW50ZXIgYW5kIHNjYWxlZCByZWFkaW5ncyBieSByZWZyYWN0b21ldGVyIikrCiAgeGxhYigiUGVyY2VudCBlcnJvciIpCgpyZWZyYWMgJT4lCiAgZ3JvdXBfYnkoUmVmcmFjdCwgT3duZXIsIFNvbHV0aW9uKSAlPiUKICBtdXRhdGUobm9ybV9yZWFkaW5nID0gKFJlYWRpbmcgLSBtZWFuKFJlYWRpbmcpKS9tZWFuKFJlYWRpbmcpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9UmVmcmFjdCwgeT1ub3JtX3JlYWRpbmcsIGNvbG9yPU93bmVyKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBmYWNldF93cmFwKH5Tb2x1dGlvbikgKwogIGdndGl0bGUoIkNlbnRlcmVkIGFuZCBzY2FsZWQiKSArCiAgeWxhYigiQ2VudGVyZWQgYW5kIHNjYWxlZCIpCgpyZWZyYWMgJT4lCiAgZmlsdGVyKCFTb2x1dGlvbiAlaW4lIGMoIkZpbHRlciBCcmV3IiwgIjIlIEZvbGdlcnMiKSkgJT4lCiAgZ3JvdXBfYnkoUmVmcmFjdCwgT3duZXIsIFNvbHV0aW9uKSAlPiUKICBtdXRhdGUobm9ybV9yZWFkaW5nID0gKFJlYWRpbmcgLSBtZWFuKFJlYWRpbmcpKS9tZWFuKFJlYWRpbmcpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9UmVmcmFjdCwgeT1ub3JtX3JlYWRpbmcsIGNvbG9yPU93bmVyKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBmYWNldF93cmFwKH5Tb2x1dGlvbikgKwogIGdndGl0bGUoIkNlbnRlcmVkIGFuZCBzY2FsZWQiKSArCiAgeWxhYigiQ2VudGVyZWQgYW5kIHNjYWxlZCIpCgojIEtub3duIHZhbHVlcyBvbmx5CnJlZnJhYyAlPiUKICBmaWx0ZXIoIWlzLm5hKEV4cGVjdGVkKSkgJT4lCiAgZ3JvdXBfYnkoUmVmcmFjdCwgT3duZXIsIFNvbHV0aW9uKSAlPiUKICBtdXRhdGUobm9ybV9yZWFkaW5nID0gKFJlYWRpbmcgLSBFeHBlY3RlZCkvRXhwZWN0ZWQgKiAxMDApICU+JQogIGdncGxvdCgpICsKICBnZW9tX2RlbnNpdHkoYWVzKG5vcm1fcmVhZGluZywgZmlsbCA9IFJlZnJhY3QpLCBhbHBoYT0wLjI1KSArCiAgZ2d0aXRsZSgiRXJyb3IgcmVsYXRpdmUgdG8gZXhwZWN0ZWQgdmFsdWUiKSsKICB4bGFiKCJQZXJjZW50IGVycm9yIikKCnJlZnJhYyAlPiUKICBmaWx0ZXIoIWlzLm5hKEV4cGVjdGVkKSkgJT4lCiAgZ3JvdXBfYnkoUmVmcmFjdCwgT3duZXIsIFNvbHV0aW9uKSAlPiUKICBtdXRhdGUobm9ybV9yZWFkaW5nID0gKFJlYWRpbmcgLSBFeHBlY3RlZCkvRXhwZWN0ZWQgKiAxMDApICU+JQogIGdncGxvdChhZXMoeD1SZWZyYWN0LCB5PW5vcm1fcmVhZGluZywgY29sb3I9T3duZXIpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGZhY2V0X3dyYXAoflNvbHV0aW9uKSArCiAgZ2d0aXRsZSgiQ29tcGFyaXNvbiBvZiByZWZyYWN0b21ldGVycyIpICsKICB5bGFiKCJQZXJjZW50IGVycm9yIikKCnJlZnJhYyAlPiUKICBmaWx0ZXIoIWlzLm5hKEV4cGVjdGVkKSkgJT4lCiAgZmlsdGVyKFNvbHV0aW9uICE9ICIyJSBGb2xnZXJzIikgJT4lCiAgZ3JvdXBfYnkoUmVmcmFjdCwgT3duZXIsIFNvbHV0aW9uKSAlPiUKICBtdXRhdGUobm9ybV9yZWFkaW5nID0gKFJlYWRpbmcgLSBFeHBlY3RlZCkvRXhwZWN0ZWQgKiAxMDApICU+JQogIGdncGxvdChhZXMoeD1SZWZyYWN0LCB5PW5vcm1fcmVhZGluZywgY29sb3I9T3duZXIpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGZhY2V0X3dyYXAoflNvbHV0aW9uKSArCiAgZ2d0aXRsZSgiQ29tcGFyaXNvbiBvZiByZWZyYWN0b21ldGVycyIpICsKICB5bGFiKCJQZXJjZW50IGVycm9yIikKCnJlZnJhYyAlPiUKICBmaWx0ZXIoIWlzLm5hKEV4cGVjdGVkKSkgJT4lCiAgZmlsdGVyKFNvbHV0aW9uICE9ICIyJSBGb2xnZXJzIikgJT4lCiAgZ3JvdXBfYnkoUmVmcmFjdCwgT3duZXIsIFNvbHV0aW9uKSAlPiUKICBtdXRhdGUobm9ybV9yZWFkaW5nID0gKFJlYWRpbmcgLSBFeHBlY3RlZCkvRXhwZWN0ZWQgKiAxMDApICU+JQogIGdncGxvdCgpICsKICBnZW9tX2RlbnNpdHkoYWVzKG5vcm1fcmVhZGluZywgZmlsbCA9IFJlZnJhY3QpLCBhbHBoYT0wLjI1KSArCiAgZ2d0aXRsZSgiTm8gMiUgRm9sZ2VycyIpKwogIHhsYWIoIlBlcmNlbnQgZXJyb3IiKQpgYGAKCgpgYGB7cn0KIyBMZXQncyBzZWUgaG93IHRoZSBlcnJvcnMgcHJvcG9nYXRlIHRvIEVZCgpleV9rZXkgPC0gdHJpYmJsZSgKICB+U29sdXRpb24sIH5yYXRpbywgfnR5cGUsCiAgIjkuOTUlIEZvbGdlcnMiLCAyLCAiOS45NSUgRm9sZ2VycyIsCiAgIjkuOTUlIEZvbGdlcnMgMiIsIDIsICI5Ljk1JSBGb2xnZXJzIiwKICAiMiUgRm9sZ2VycyIsIDEwLCAiMiUgRm9sZ2VycyIKICAKKQoKcmVmcmFjICU+JQogIGZpbHRlcihTb2x1dGlvbiAlaW4lIGMoIjkuOTUlIEZvbGdlcnMiLCAiOS45NSUgRm9sZ2VycyAyIiwgIjIlIEZvbGdlcnMiKSkgJT4lCiAgbGVmdF9qb2luKGV5X2tleSwgYnk9IlNvbHV0aW9uIikgJT4lCiAgbXV0YXRlKHByZWRpY3RlZF9leSA9IFJlYWRpbmcgKiByYXRpbykgJT4lCiAgbXV0YXRlKGV4cGVjdGVkX2V5ID0gRXhwZWN0ZWQgKiByYXRpbykgJT4lCiAgbXV0YXRlKGRpZmZfZnJvbV9leHBlY3RlZCA9IHByZWRpY3RlZF9leSAtIGV4cGVjdGVkX2V5KSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9kZW5zaXR5KGFlcyhkaWZmX2Zyb21fZXhwZWN0ZWQsIGZpbGw9UmVmcmFjdCksIGFscGhhPTAuMjUpICsKICBnZ3RpdGxlKCJFcnJvciBpbiBFeHRyYWN0aW9uIFlpZWxkICglKSwgRm9sZ2VycyBJbnN0YW50IikgKwogIHhsYWIoIk9ic2VydmVkIEVZIC0gRXhwZWN0ZWQgRVkiKQoKcmVmcmFjICU+JQogIGZpbHRlcihTb2x1dGlvbiAlaW4lIGMoIjkuOTUlIEZvbGdlcnMiLCAiOS45NSUgRm9sZ2VycyAyIiwgIjIlIEZvbGdlcnMiKSkgJT4lCiAgbGVmdF9qb2luKGV5X2tleSwgYnk9IlNvbHV0aW9uIikgJT4lCiAgbXV0YXRlKHByZWRpY3RlZF9leSA9IFJlYWRpbmcgKiByYXRpbykgJT4lCiAgbXV0YXRlKGV4cGVjdGVkX2V5ID0gRXhwZWN0ZWQgKiByYXRpbykgJT4lCiAgbXV0YXRlKGRpZmZfZnJvbV9leHBlY3RlZCA9IHByZWRpY3RlZF9leSAtIGV4cGVjdGVkX2V5KSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChhZXMoeD1leHBlY3RlZF9leSwgeT1wcmVkaWN0ZWRfZXksIGNvbG9yPVJlZnJhY3QpKSArCiAgZ2d0aXRsZSgiRXJyb3IgaW4gRXh0cmFjdGlvbiBZaWVsZCglKSwgRm9sZ2VycyBJbnN0YW50IikKCnJhdGlvX2V4cGFuc2lvbiA8LSBleV9rZXkgJT4lCiAgZXhwYW5kKFNvbHV0aW9uLCByYXRpbz01OjE1KSAlPiUKICBsZWZ0X2pvaW4oc2VsZWN0KGV5X2tleSwgU29sdXRpb24sIHR5cGUpKQoKcmVmcmFjICU+JQogIGZpbHRlcihTb2x1dGlvbiAlaW4lIGMoIjIlIEZvbGdlcnMiKSkgJT4lCiAgbGVmdF9qb2luKHJhdGlvX2V4cGFuc2lvbiwgYnk9IlNvbHV0aW9uIikgJT4lCiAgbXV0YXRlKHByZWRpY3RlZF9leSA9IFJlYWRpbmcgKiByYXRpbykgJT4lCiAgbXV0YXRlKGV4cGVjdGVkX2V5ID0gRXhwZWN0ZWQgKiByYXRpbykgJT4lCiAgbXV0YXRlKGRpZmZfZnJvbV9leHBlY3RlZCA9IHByZWRpY3RlZF9leSAtIGV4cGVjdGVkX2V5KSAlPiUKICBncm91cF9ieShleHBlY3RlZF9leSwgUmVmcmFjdCwgcmF0aW8pICU+JQogIHN1bW1hcmlzZShtZWFuX29icyA9IG1lYW4ocHJlZGljdGVkX2V5KSwKICAgICAgICAgICAgc2RfaGlnaF9vYnMgPSBtZWFuKHByZWRpY3RlZF9leSkgKyBzZChwcmVkaWN0ZWRfZXkgKiAyKSwKICAgICAgICAgICAgc2RfbG93X29icyA9IG1lYW4ocHJlZGljdGVkX2V5KSAtIHNkKHByZWRpY3RlZF9leSAqIDIpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgZ2dwbG90KGFlcyh4PWV4cGVjdGVkX2V5LCB5PW1lYW5fb2JzLCBjb2xvcj1SZWZyYWN0KSkgKwogIGdlb21fbGluZSgpICsKICBnZW9tX3JpYmJvbihhZXMoeW1pbj1zZF9sb3dfb2JzLCB5bWF4PXNkX2hpZ2hfb2JzLCBmaWxsPVJlZnJhY3QpLCBhbHBoYT0wLjI1LCBjb2xvcj1OQSkgKwogIGdlb21fYWJsaW5lKCkgKwogIGdndGl0bGUoIkVycm9yIGluIEV4dHJhY3Rpb24gWWllbGQoJSksIEZvbGdlcnMgSW5zdGFudCAyJSBURCwgMiBzZCByaWJib24iKQoKcmVmcmFjICU+JQogIGZpbHRlcihTb2x1dGlvbiAlaW4lIGMoIjIlIEZvbGdlcnMiKSkgJT4lCiAgbGVmdF9qb2luKHJhdGlvX2V4cGFuc2lvbiwgYnk9IlNvbHV0aW9uIikgJT4lCiAgbXV0YXRlKHByZWRpY3RlZF9leSA9IFJlYWRpbmcgKiByYXRpbykgJT4lCiAgbXV0YXRlKGV4cGVjdGVkX2V5ID0gRXhwZWN0ZWQgKiByYXRpbykgJT4lCiAgbXV0YXRlKGRpZmZfZnJvbV9leHBlY3RlZCA9IHByZWRpY3RlZF9leSAtIGV4cGVjdGVkX2V5KSAlPiUKICBncm91cF9ieShPd25lciwgZXhwZWN0ZWRfZXksIFJlZnJhY3QsIHJhdGlvKSAlPiUKICBzdW1tYXJpc2UobWVhbl9vYnMgPSBtZWFuKHByZWRpY3RlZF9leSksCiAgICAgICAgICAgIHNkX2hpZ2hfb2JzID0gbWVhbihwcmVkaWN0ZWRfZXkpICsgc2QocHJlZGljdGVkX2V5ICogMiksCiAgICAgICAgICAgIHNkX2xvd19vYnMgPSBtZWFuKHByZWRpY3RlZF9leSkgLSBzZChwcmVkaWN0ZWRfZXkgKiAyKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZShpbnN0cnVtZW50ID0gcGFzdGUoUmVmcmFjdCwgT3duZXIpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9ZXhwZWN0ZWRfZXksIHk9bWVhbl9vYnMsIGNvbG9yPWluc3RydW1lbnQpKSArCiAgZ2VvbV9yaWJib24oYWVzKHltaW49c2RfbG93X29icywgeW1heD1zZF9oaWdoX29icywgZmlsbD1pbnN0cnVtZW50KSwgYWxwaGE9MC4yNSwgY29sb3I9TkEpICsKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9hYmxpbmUoKSArCiAgZ2d0aXRsZSgiRXJyb3IgaW4gRXh0cmFjdGlvbiBZaWVsZCglKSwgRm9sZ2VycyBJbnN0YW50IDIlIFREUywgMiBzZCByaWJib24iKSArCiAgZmFjZXRfd3JhcCh+UmVmcmFjdCwgbmNvbD0xKQoKcmVmcmFjICU+JQogIGZpbHRlcihTb2x1dGlvbiAlaW4lIGMoIjIlIEZvbGdlcnMiKSkgJT4lCiAgbGVmdF9qb2luKHJhdGlvX2V4cGFuc2lvbiwgYnk9IlNvbHV0aW9uIikgJT4lCiAgbXV0YXRlKHByZWRpY3RlZF9leSA9IFJlYWRpbmcgKiByYXRpbykgJT4lCiAgbXV0YXRlKGV4cGVjdGVkX2V5ID0gRXhwZWN0ZWQgKiByYXRpbykgJT4lCiAgbXV0YXRlKGRpZmZfZnJvbV9leHBlY3RlZCA9IHByZWRpY3RlZF9leSAtIGV4cGVjdGVkX2V5KSAlPiUKICBncm91cF9ieShPd25lciwgZXhwZWN0ZWRfZXksIFJlZnJhY3QsIHJhdGlvKSAlPiUKICBzdW1tYXJpc2UobWVkX29icyA9IG1lZGlhbihwcmVkaWN0ZWRfZXkpLAogICAgICAgICAgICBoaWdoX29icyA9IG1heChwcmVkaWN0ZWRfZXkpLAogICAgICAgICAgICBsb3dfb2JzID0gbWluKHByZWRpY3RlZF9leSkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUoaW5zdHJ1bWVudCA9IHBhc3RlKFJlZnJhY3QsIE93bmVyKSkgJT4lCiAgZ2dwbG90KGFlcyh4PWV4cGVjdGVkX2V5LCB5PW1lZF9vYnMsIGNvbG9yPWluc3RydW1lbnQpKSArCiAgZ2VvbV9yaWJib24oYWVzKHltaW49bG93X29icywgeW1heD1oaWdoX29icywgZmlsbD1pbnN0cnVtZW50KSwgYWxwaGE9MC4yNSwgY29sb3I9TkEpICsKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9hYmxpbmUoKSArCiAgZ2d0aXRsZSgiRXJyb3IgaW4gRXh0cmFjdGlvbiBZaWVsZCglKSwgRm9sZ2VycyBJbnN0YW50IDIlIFREUywgbWluL21heCByaWJib24iKSArCiAgZmFjZXRfd3JhcCh+UmVmcmFjdCkKCgpyYXRpb19leHBhbnNpb24gPC0gZXlfa2V5ICU+JQogIGV4cGFuZChTb2x1dGlvbiwgcmF0aW89KDE1OjI4KS8xMCkgJT4lCiAgbGVmdF9qb2luKHNlbGVjdChleV9rZXksIFNvbHV0aW9uLCB0eXBlKSkKCnJlZnJhYyAlPiUKICBmaWx0ZXIoU29sdXRpb24gJWluJSBjKCI5Ljk1JSBGb2xnZXJzIiwgIjkuOTUlIEZvbGdlcnMgMiIpKSAlPiUKICAgIGxlZnRfam9pbihyYXRpb19leHBhbnNpb24sIGJ5PSJTb2x1dGlvbiIpICU+JQogIG11dGF0ZShwcmVkaWN0ZWRfZXkgPSBSZWFkaW5nICogcmF0aW8pICU+JQogIG11dGF0ZShleHBlY3RlZF9leSA9IEV4cGVjdGVkICogcmF0aW8pICU+JQogIG11dGF0ZShkaWZmX2Zyb21fZXhwZWN0ZWQgPSBwcmVkaWN0ZWRfZXkgLSBleHBlY3RlZF9leSkgJT4lCiAgZ3JvdXBfYnkoZXhwZWN0ZWRfZXksIFJlZnJhY3QsIHJhdGlvKSAlPiUKICBzdW1tYXJpc2UobWVhbl9vYnMgPSBtZWFuKHByZWRpY3RlZF9leSksCiAgICAgICAgICAgIHNkX2hpZ2hfb2JzID0gbWVhbihwcmVkaWN0ZWRfZXkpICsgc2QocHJlZGljdGVkX2V5KSAqIDIsCiAgICAgICAgICAgIHNkX2xvd19vYnMgPSBtZWFuKHByZWRpY3RlZF9leSkgLSBzZChwcmVkaWN0ZWRfZXkpICogMikgJT4lCiAgdW5ncm91cCgpICU+JQogIGdncGxvdChhZXMoeD1leHBlY3RlZF9leSwgeT1tZWFuX29icywgY29sb3I9UmVmcmFjdCkpICsKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9hYmxpbmUoKSArCiAgZ2VvbV9yaWJib24oYWVzKHltaW49c2RfbG93X29icywgeW1heD1zZF9oaWdoX29icywgZmlsbD1SZWZyYWN0KSwgYWxwaGE9MC4yNSwgY29sb3I9TkEpICsKICBnZ3RpdGxlKCJFcnJvciBpbiBFeHRyYWN0aW9uIFlpZWxkKCUpLCBGb2xnZXJzIEluc3RhbnQgOS45NSUgVERTLCAyIHNkIHJpYmJvbiIpCgpyZWZyYWMgJT4lCiAgZmlsdGVyKFNvbHV0aW9uICVpbiUgYygiOS45NSUgRm9sZ2VycyIsICI5Ljk1JSBGb2xnZXJzIDIiKSkgJT4lCiAgICBsZWZ0X2pvaW4ocmF0aW9fZXhwYW5zaW9uLCBieT0iU29sdXRpb24iKSAlPiUKICBtdXRhdGUocHJlZGljdGVkX2V5ID0gUmVhZGluZyAqIHJhdGlvKSAlPiUKICBtdXRhdGUoZXhwZWN0ZWRfZXkgPSBFeHBlY3RlZCAqIHJhdGlvKSAlPiUKICBtdXRhdGUoZGlmZl9mcm9tX2V4cGVjdGVkID0gcHJlZGljdGVkX2V5IC0gZXhwZWN0ZWRfZXkpICU+JQogIGdyb3VwX2J5KE93bmVyLCBleHBlY3RlZF9leSwgUmVmcmFjdCwgcmF0aW8pICU+JQogIHN1bW1hcmlzZShtZWFuX29icyA9IG1lYW4ocHJlZGljdGVkX2V5KSwKICAgICAgICAgICAgc2RfaGlnaF9vYnMgPSBtZWFuKHByZWRpY3RlZF9leSkgKyBzZChwcmVkaWN0ZWRfZXkpICogMiwKICAgICAgICAgICAgc2RfbG93X29icyA9IG1lYW4ocHJlZGljdGVkX2V5KSAtIHNkKHByZWRpY3RlZF9leSkgKiAyKSAlPiUKICAgIG11dGF0ZShpbnN0cnVtZW50ID0gcGFzdGUoUmVmcmFjdCwgT3duZXIpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9ZXhwZWN0ZWRfZXksIHk9bWVhbl9vYnMsIGNvbG9yPWluc3RydW1lbnQpKSArCiAgZ2VvbV9yaWJib24oYWVzKHltaW49c2RfbG93X29icywgeW1heD1zZF9oaWdoX29icywgZmlsbD1pbnN0cnVtZW50KSwgYWxwaGE9MC4yNSwgY29sb3I9TkEpICsKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9hYmxpbmUoKSArCiAgZ2d0aXRsZSgiRXJyb3IgaW4gRXh0cmFjdGlvbiBZaWVsZCglKSwgRm9sZ2VycyBJbnN0YW50IDkuOTUlIFREUywgMiBzZCByaWJib24iKSArCiAgZmFjZXRfd3JhcCh+UmVmcmFjdCwgbmNvbD0xKQoKcmVmcmFjICU+JQogIGZpbHRlcihTb2x1dGlvbiAlaW4lIGMoIjkuOTUlIEZvbGdlcnMiLCAiOS45NSUgRm9sZ2VycyAyIikpICU+JQogIGxlZnRfam9pbihyYXRpb19leHBhbnNpb24sIGJ5PSJTb2x1dGlvbiIpICU+JQogIG11dGF0ZShwcmVkaWN0ZWRfZXkgPSBSZWFkaW5nICogcmF0aW8pICU+JQogIG11dGF0ZShleHBlY3RlZF9leSA9IEV4cGVjdGVkICogcmF0aW8pICU+JQogIG11dGF0ZShkaWZmX2Zyb21fZXhwZWN0ZWQgPSBwcmVkaWN0ZWRfZXkgLSBleHBlY3RlZF9leSkgJT4lCiAgZ3JvdXBfYnkoT3duZXIsIGV4cGVjdGVkX2V5LCBSZWZyYWN0LCByYXRpbykgJT4lCiAgc3VtbWFyaXNlKG1lZF9vYnMgPSBtZWRpYW4ocHJlZGljdGVkX2V5KSwKICAgICAgICAgICAgaGlnaF9vYnMgPSBtYXgocHJlZGljdGVkX2V5KSwKICAgICAgICAgICAgbG93X29icyA9IG1pbihwcmVkaWN0ZWRfZXkpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKGluc3RydW1lbnQgPSBwYXN0ZShSZWZyYWN0LCBPd25lcikpICU+JQogIGdncGxvdChhZXMoeD1leHBlY3RlZF9leSwgeT1tZWRfb2JzLCBjb2xvcj1pbnN0cnVtZW50KSkgKwogIGdlb21fcmliYm9uKGFlcyh5bWluPWxvd19vYnMsIHltYXg9aGlnaF9vYnMsIGZpbGw9aW5zdHJ1bWVudCksIGFscGhhPTAuMjUsIGNvbG9yPU5BKSArCiAgZ2VvbV9saW5lKCkgKwogIGdlb21fYWJsaW5lKCkgKwogIGdndGl0bGUoIkVycm9yIGluIEV4dHJhY3Rpb24gWWllbGQoJSksIEZvbGdlcnMgSW5zdGFudCA5Ljk1JSBURFMsIG1pbi9tYXggcmliYm9uIikgKwogIGZhY2V0X3dyYXAoflJlZnJhY3QsIG5jb2w9MSkKYGBgCgoKYGBge3J9CgpgYGA=